package com.gitee.huanminabc.dynamicdb.core;

import com.gitee.huanminabc.dynamicdb.common.Constants;
import com.gitee.huanminabc.dynamicdb.common.DynamicDbException;
import com.gitee.huanminabc.dynamicdb.common.SpringContextHolder;
import com.gitee.huanminabc.dynamicdb.config.DynamicDbSpringConfig;
import com.gitee.huanminabc.dynamicdb.entity.DataSourceEneity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
 * @author huanmin
 * @date 2024/11/22
 */
/**
 * 手动添加数据源配置
 */
@Slf4j
public class DynamicDataSourceContext{

    //全部的数据源
    private static final Map<Object, Object> dataSources = new HashMap<>();
    //配置信息
    private static final Map<String, DataSourceProperties> dataSourceEneityHashMap = new HashMap<>();

    /**
     * 动态添加一个数据源
     *
     * @param key       数据源的key
     * @param dataSource 数据源对象
     */
    public static synchronized void addDataSource(String key, DataSource dataSource, DataSourceProperties dataSourceEneity) {
        String dbKey= Constants.MULTI_DB_PREFIX +key;
        //判断数据源是否存在
        if (containsDataSource(dbKey)) {
            log.error("[DynamicDataSourceService->addDataSource] 注册的数据源已存在 key:{} ", dbKey);
            return;
        }
        //添加到数据源容器中
        dataSourceEneityHashMap.put(dbKey, dataSourceEneity);

        //添加到动态数据源中
        DynamicDataSource dynamicDataSource = SpringContextHolder.getApplicationContext().getBean(DynamicDataSource.class);
        dataSources.put(dbKey, dataSource);
        dynamicDataSource.setTargetDataSources(dataSources);
        dynamicDataSource.afterPropertiesSet();
    }

    //批量加载
    public static synchronized void addDataSource(Map<String, DataSourceProperties> dataSourceMap) {
        //添加到动态数据源中
        DynamicDataSource dynamicDataSource = SpringContextHolder.getApplicationContext().getBean(DynamicDataSource.class);
        dynamicDataSource.setTargetDataSources(dataSources);
        dataSourceMap.forEach((key, dataSourceProperties) -> {
            String dbKey= Constants.MULTI_DB_PREFIX +key;
            DataSource dataSource = buildDataSource(dataSourceProperties);
            //添加到数据源容器中
            dataSourceEneityHashMap.put(dbKey, dataSourceProperties);
            dataSources.put(dbKey, dataSource);
        });
        //初始化数据源
        dynamicDataSource.afterPropertiesSet();
    }

    /**
     * @param key            数据源的key
     * @param driverClassName 驱动
     * @param url             数据库连接地址
     * @param username        数据库账户
     * @param password        数据库密码
     */
    public static synchronized void addDataSource(String key, String driverClassName, String url, String username, String password) {
        String dbKey= Constants.MULTI_DB_PREFIX +key;
        DataSourceBuilder<?> builder = DataSourceBuilder.create();
        builder.driverClassName(driverClassName);
        builder.username(username);
        builder.password(password);
        builder.url(url);
        DataSourceProperties dataSourceProperties = new DataSourceProperties();
        dataSourceProperties.setDriverClassName(driverClassName);
        dataSourceProperties.setUsername(username);
        dataSourceProperties.setPassword(password);
        dataSourceProperties.setUrl(url);
        addDataSource(dbKey, builder.build(), dataSourceProperties);
    }



    //获取指定key的数据源
    public static DataSource getDataSource(String key) {
        String dbKey= Constants.MULTI_DB_PREFIX +key;
        return (DataSource) dataSources.get(dbKey);
    }

    /**
     * 获取指定key的数据源信息
     */
    public static DataSourceProperties getDataSourceProperties(String key) {
        String dbKey= Constants.MULTI_DB_PREFIX +key;
        return dataSourceEneityHashMap.get(dbKey);

    }
    //判断数据源是否存在
    public static boolean containsDataSource(String key) {
        String dbKey= Constants.MULTI_DB_PREFIX +key;
        return dataSources.containsKey(dbKey);
    }

    //获取全部的数据源
    public static  Map<String, DataSourceProperties> getAllDataSource() {
        return dataSourceEneityHashMap;
    }




    public static DataSource buildDataSource(DataSourceProperties prop) {
        DataSourceBuilder<?> builder = DataSourceBuilder.create();
        builder.driverClassName(prop.getDriverClassName());
        builder.username(prop.getUsername());
        builder.password(prop.getPassword());
        builder.url(prop.getUrl());
        builder.type(prop.getType());
        return builder.build();
    }




    public static synchronized DataSourceProperties  buildMultiDbDataSource(DynamicDbSpringConfig.MultiDbDataSource multiDbDataSource){
        DataSourceProperties dataSourceProperties = new DataSourceProperties();
        dataSourceProperties.setUrl(multiDbDataSource.getUrl());
        dataSourceProperties.setUsername(multiDbDataSource.getUsername());
        dataSourceProperties.setPassword(multiDbDataSource.getPassword());
        dataSourceProperties.setDriverClassName(multiDbDataSource.getDriverClassName());
        try {
            Class aClass = Class.forName(multiDbDataSource.getType());
            dataSourceProperties.setType(aClass);
        } catch (ClassNotFoundException e) {
            throw new DynamicDbException(e);
        }

        return dataSourceProperties;
    }
    public static synchronized DataSourceProperties  buildMultiDbDataSource(DataSourceEneity multiDbDataSource){
        DataSourceProperties dataSourceProperties = new DataSourceProperties();
        dataSourceProperties.setUrl(multiDbDataSource.getUrl());
        dataSourceProperties.setUsername(multiDbDataSource.getUsername());
        dataSourceProperties.setPassword(multiDbDataSource.getPassword());
        dataSourceProperties.setDriverClassName(multiDbDataSource.getDriverClassName());
        try {
            Class aClass = Class.forName(multiDbDataSource.getType());
            dataSourceProperties.setType(aClass);
        } catch (ClassNotFoundException e) {
            throw new DynamicDbException(e);
        }

        return dataSourceProperties;
    }
}
